package cn.tedu.jsd2210.csmall.passport.service.impl;

import cn.tedu.jsd2210.csmall.passport.ex.ServiceException;
import cn.tedu.jsd2210.csmall.passport.mapper.AdminMapper;
import cn.tedu.jsd2210.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.jsd2210.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.jsd2210.csmall.passport.pojo.dto.AdminLoginInfoDTO;
import cn.tedu.jsd2210.csmall.passport.pojo.entity.Admin;
import cn.tedu.jsd2210.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.jsd2210.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.jsd2210.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.jsd2210.csmall.passport.security.AdminDetails;
import cn.tedu.jsd2210.csmall.passport.service.IAdminService;
import cn.tedu.jsd2210.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 处理管理员数据的业务实现类
 *
 * @author java@tedu.cn
 * @version 0.0.1
 */
@Slf4j
@Service
public class  AdminServiceImpl implements IAdminService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    public AdminServiceImpl() {
        log.debug("创建业务类对象：AdminServiceImpl");
    }
    /**
     * 管理员登录
     * @param adminLoginInfoDTO 封装了用户名、密码等相关信息的对象
     * @return 此管理员登录后得到的JWT数据
     */
    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理[管理员登录]的业务,参数:{}",adminLoginInfoDTO);
        Authentication authentication=new UsernamePasswordAuthenticationToken(
                adminLoginInfoDTO.getUsername(),adminLoginInfoDTO.getPassword()
        );
        Authentication authenticateResult=
                authenticationManager.authenticate(authentication);
        log.debug("认证通过！（如果未通过，过程中将抛出异常，你不会看到此条日志！）");
        log.debug("认证结果:{}",authenticateResult);
        log.debug("认证结果中的当事人：{}", authenticateResult.getPrincipal());
        //使用JWT机制时，登录成功后不再需要将认证信息存入到
        //        SecurityContext securityContext= SecurityContextHolder.getContext();
        //        securityContext.setAuthentication(authenticateResult);

        // 需要存入到JWT中的数据
        AdminDetails adminDetails=(AdminDetails)authenticateResult.getPrincipal();
        Map<String,Object> claims=new HashMap<>();
        claims.put("id",adminDetails.getId());
        claims.put("username",adminDetails.getUsername());
        // 权限待定

        String authoritiesJsonString=JSON.toJSONString(adminDetails.getAuthorities());
        claims.put("authoritiesJsonString", authoritiesJsonString);

        // 生成JWT，以下代码是相对固定的

        String jwt = Jwts.builder()
                // Header：声明算法与Token类型
                .setHeaderParam("alg","HS256")
                .setHeaderParam("tye","JWT")
                // Payload：数据，具体表现为Claims
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis()+durationInMinute*60*1000) )
                // Verify Signature：验证签名
                .signWith(SignatureAlgorithm.HS256,secretKey)
                .compact();
        log.debug("生成了JWT数据：{}", jwt);
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDto) {
        //通过参数的得到校色ID数组
        Long[] roleIds = adminAddNewDto.getRoleIds();
        for (Long roleId : roleIds) {
            if(roleId==1){
                String message = "添加管理员失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERROR_INSERT, message);
            }
        }

        {        // 从参数对象中获取管理员的用户名
            String username = adminAddNewDto.getUsername();
            // 调用Mapper对象的countByUsername()执行统计
            int count = adminMapper.countByUsername(username);
            // 判断统计结果是否大于0
            if (count > 0) {
                // 是：抛出异常
                String message = "添加管理员失败，用户名已经被占用！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
            }
        }

        {
            String phone = adminAddNewDto.getPhone();
            int count = adminMapper.countByPhone(phone);
            if (count > 0) {
                String message = "添加管理员失败，手机已经被占用！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
            }
        }

        {
            String email = adminAddNewDto.getEmail();
            int count = adminMapper.countByEmail(email);
            if (count > 0) {
                String message = "添加管理员失败，邮箱已经被占用！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
            }
        }
        Admin admin=new Admin();
        BeanUtils.copyProperties(adminAddNewDto,admin);
        admin.setLoginCount(0);
        // 从Admin对象中取出原密码，执行加密，再将密文存入到Admin对象中
        String rawPassword= admin.getPassword();
        String encodePassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodePassword);

        int rows = adminMapper.insert(admin);
        if(rows!=1){
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }


        //基于ID数组创建List<AdminRole>
        List<AdminRole> adminRoleList =new ArrayList<>();
        for (Long roleId : roleIds) {
            //为新添加的管理员分配角色
            AdminRole adminRole=new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleId);
            adminRoleList.add(adminRole);
        }
        //调用AdminRoleMapper对象的insertBatch()执行插入
        rows = adminRoleMapper.insertBatch(adminRoleList);
        if(rows<1){
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }

    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理[删除管理员]的业务,参数:{}",id);
        Object queryResult = adminMapper.getStandardById(id);
        if(id==1){
            String message="删除管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }

        if(queryResult==null){
            String message="删除管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }

        int rows = adminMapper.deleteById(id);
        if(rows!=1){
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE, message);
        }
        // 执行删除--管理员与角色的关联表
        log.debug("即将执行删除关联数据,参数:{}",id);
        rows = adminRoleMapper.deleteByAdminId(id);
        if(rows < 1){
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE, message);
        }
    }

//    @Override
//    public AdminStandardVO getStandardById(Long id) {
//        return null;
//    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理[查询管理员列表]的业务,无参数");
        List<AdminListItemVO> list= adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            AdminListItemVO item=iterator.next();
            if(item.getId()==1){
                iterator.remove();
                break;
            }
        }
        return list;
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id,0);
    }

    public void updateEnableById(Long id,Integer enable) {
        if(id==1){
            String message="修改管理员失败,尝试修改的管理员数据不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }

        //调用mapper对象的getStandardById方法查询
        AdminStandardVO currentAdmin = adminMapper.getStandardById(id);
        //判断结果是否为null,是则抛出异常
        if(currentAdmin==null){
            String message="修改管理员失败,尝试修改的管理员数据不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }
        //判断查询结果中的enable与参数enable是否相同,是则抛出异常(当前状态与目标状态相同,没必要修改)
        Integer currentEnable = currentAdmin.getEnable();
        if(currentEnable==enable){
            String message=ENABLE_TEXT[enable]+"失败,此管理员已经处于该状态!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        //创建category对象
        Admin updateAdmin=new Admin();
        //向对象封装属性
        updateAdmin.setId(id);
        updateAdmin.setEnable(enable);
        //调用mapper方法进行更新
        int rows = adminMapper.update(updateAdmin);
        if(rows!=1){
            String message="修改管理员失败,服务器忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE,message);
        }
    }
}
